package com.lnu_devteam.zongce.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lnu_devteam.zongce.common.ErrorCode;
import com.lnu_devteam.zongce.common.PageRequest;
import com.lnu_devteam.zongce.constant.CommonConstant;
import com.lnu_devteam.zongce.constant.ScoreConstant;
import com.lnu_devteam.zongce.exception.BusinessException;
import com.lnu_devteam.zongce.mapper.ScoreMapper;
import com.lnu_devteam.zongce.model.dto.ScoreIncreaseDTO;
import com.lnu_devteam.zongce.model.entity.Score;
import com.lnu_devteam.zongce.model.entity.User;
import com.lnu_devteam.zongce.model.enums.RoleEnum;
import com.lnu_devteam.zongce.model.vo.ScoreVO;
import com.lnu_devteam.zongce.service.ScoreService;
import com.lnu_devteam.zongce.service.UserService;
import com.lnu_devteam.zongce.utils.FuncUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author xbaoziplus
 * @description 针对表【tb_score(分数表)】的数据库操作Service实现
 * @createDate 2023-03-23 11:48:19
 */
@Service
public class ScoreServiceImpl extends ServiceImpl<ScoreMapper, Score>
        implements ScoreService {

    @Resource
    private UserService userService;

    @Override
    public boolean audit(Long scoreId, int auditStatus, String reason, HttpServletRequest request) {
        if (scoreId == null || scoreId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Score scoreEntity = getOne(new LambdaQueryWrapper<Score>().select(Score::getSId).eq(Score::getSId, scoreId));
        if (scoreEntity == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        scoreEntity.setSStatus(auditStatus);
        scoreEntity.setSExtra(reason);
        scoreEntity.setUpdateUser(loginUser.getUAccount());
        return updateById(scoreEntity);
    }

    @Override
    public Page<ScoreVO> pageScoreApply(PageRequest pageRequest, String pageType, String scoreType, String changeType) {
        if (pageRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 数据校验
        int currentPage = pageRequest.getCurrentPage();
        int pageSize = pageRequest.getPageSize();
        FuncUtils.isTrueToThr(currentPage <= 0 || pageSize <= 0).throwException(ErrorCode.PARAMS_ERROR);
        int pageIntType, scoreIntType, changeIntType;
        try {
            pageIntType = Integer.parseInt(pageType);
            scoreIntType = Integer.parseInt(scoreType);
            changeIntType = Integer.parseInt(changeType);
        } catch (NumberFormatException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 条件设置，支持学号右模糊查询
        LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<Score>()
                .eq(pageIntType != ScoreConstant.ALL_SCORE_HISTORY, Score::getSStatus, pageIntType)
                .eq(scoreIntType != ScoreConstant.ALL_SCORE_TYPE, Score::getSType, scoreIntType)
                .lt(changeIntType == ScoreConstant.DECREASE_TYPE, Score::getSValue, 0)
                .gt(changeIntType == ScoreConstant.INCREASE_TYPE, Score::getSValue, 0)
                // 模糊搜索，支持学号右模糊查、奖项名全模糊查和类型查(德育、技能、文体)
                .and(StringUtils.isNotBlank(pageRequest.getKey()), andWrapper -> {
                    andWrapper.likeRight(Score::getCreateUser, pageRequest.getKey())
                            .or()
                            .like(Score::getSProject, pageRequest.getKey())
                            .or()
                            .eq(Score::getSType, getScoreTypeFromKey(pageRequest.getKey()));
                });
        // 权限控制
        if (loginUser.getUAuth().equals(RoleEnum.USER.getAuth())) {
            wrapper.eq(Score::getCreateUser, loginUser.getUAccount());
        }
        // 数据拷贝
        Page<Score> scorePage = page(new Page<>(currentPage, pageSize), wrapper.orderByDesc(Score::getUpdateTime));
        Page<ScoreVO> scoreVOPage = new Page<>(currentPage, pageSize);
        BeanUtils.copyProperties(scorePage, scoreVOPage, "records");
        // 数据清洗
        ScoreVO scoreVOPrototype = new ScoreVO();
        scoreVOPage.setRecords(
                scorePage.getRecords().stream().map((item) -> {
                    ScoreVO scoreVOClone = scoreVOPrototype.clone();
                    BeanUtils.copyProperties(item, scoreVOClone);
                    // 反序列化证明材料
                    List<String> supportList = new Gson().fromJson(item.getSSupport(), new TypeToken<List<String>>() {}.getType());
                    scoreVOClone.setSSupport(supportList);
                    // 创建人和更新人补充姓名
                    User createUser = userService.getOne(new LambdaQueryWrapper<User>().select(User::getUName).eq(User::getUAccount, item.getCreateUser()));
                    scoreVOClone.setCreateUserName(createUser.getUName());
                    if (item.getCreateUser().equals(item.getUpdateUser())) {
                        //scoreVOClone.setUpdateUser("-");
                        scoreVOClone.setUpdateUserName(createUser.getUName());
                        //scoreVOClone.setUpdateTime(null);
                        return scoreVOClone;
                    }
                    User updateUser = userService.getOne(new LambdaQueryWrapper<User>().select(User::getUName).eq(User::getUAccount, item.getUpdateUser()));
                    scoreVOClone.setUpdateUserName(updateUser.getUName());
                    return scoreVOClone;
                }).collect(Collectors.toList())
        );
        return scoreVOPage;
    }

    @Override
    public boolean recallScoreApply(Long scoreId, HttpServletRequest request) {
        if (scoreId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Score scoreEntity = getOne(new LambdaQueryWrapper<Score>().select(Score::getSId, Score::getCreateUser).eq(Score::getSId, scoreId));
        User loginUser = userService.getLoginUser(request);
        // 只允许自己删除
        if (loginUser == null || !scoreEntity.getCreateUser().equals(loginUser.getUAccount())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        return removeById(scoreId);
    }

    @Override
    public boolean changeScore(ScoreIncreaseDTO scoreChangeDTO, String uAccount, int changeType) {
        // 参数校验
        changeScoreVerify(scoreChangeDTO);
        Score score = new Score();
        BeanUtils.copyProperties(scoreChangeDTO, score);
        // 设置加分材料
        score.setSSupport(new Gson().toJson(scoreChangeDTO.getSSupport()));
        // 设置用户信息
        User loginUser = userService.getLoginUser();
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        score.setSCollege(loginUser.getUCollege());
        score.setSGrade(loginUser.getUGrade());
        score.setSMajor(loginUser.getUMajor());
        score.setSClass(loginUser.getUClass());
        score.setCreateUser(loginUser.getUAccount());
        score.setUpdateUser(loginUser.getUAccount());
        // 判断是否是扣分
        if (changeType == ScoreConstant.DECREASE_TYPE) {
            // 分数取负数
            score.setSValue(scoreChangeDTO.getSValue() * -1);
            // 设置扣分者信息
            User decreaseUser = userService.getOne(
                    new LambdaQueryWrapper<User>()
                            .select(User::getUCollege, User::getUGrade, User::getUMajor, User::getUClass)
                            .eq(User::getUAccount, uAccount)
            );
            score.setSCollege(decreaseUser.getUCollege());
            score.setSGrade(decreaseUser.getUGrade());
            score.setSMajor(decreaseUser.getUMajor());
            score.setSClass(decreaseUser.getUClass());
            // 创建者修改成扣分目标
            score.setCreateUser(uAccount);
            // 因为是管理员扣分，直接审批通过
            score.setSStatus(ScoreConstant.AUDIT_APPROVED);
            // 设置管理员
            score.setUpdateUser(userService.getLoginUserAccount());
            score.setSExtra(ScoreConstant.DEFAULT_REASON);
        }
        // 保存信息
        boolean isSave = save(score);
        FuncUtils.isTrueToThr(!isSave).throwException(ErrorCode.OPERATION_ERROR);
        return true;
    }

    private static void changeScoreVerify(ScoreIncreaseDTO scoreIncreaseDTO) {
        if (scoreIncreaseDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (scoreIncreaseDTO.getSValue() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (scoreIncreaseDTO.getSType() < ScoreConstant.MORAL_TYPE || scoreIncreaseDTO.getSType() > ScoreConstant.ARTS_AND_SPORT_TYPE) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (scoreIncreaseDTO.getSSupport().size() > ScoreConstant.MAX_SUPPORT_SIZE) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        for (String supportUrl : scoreIncreaseDTO.getSSupport()) {
            if (!Pattern.compile(CommonConstant.URL_PATTERN).matcher(supportUrl).matches()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
        }
    }

    private int getScoreTypeFromKey(String key) {
        if (ScoreConstant.MORAL_KEY_LIST.contains(key)) {
            return ScoreConstant.MORAL_TYPE;
        } else if (ScoreConstant.SKILL_KEY_LIST.contains(key)) {
            return ScoreConstant.SKILL_TYPE;
        } else if (ScoreConstant.ARTS_AND_SPORT_KEY_LIST.contains(key)) {
            return  ScoreConstant.ARTS_AND_SPORT_TYPE;
        } else {
            return ScoreConstant.ALL_SCORE_TYPE;
        }
    }
}




